//Copyright 2010 Neurosciences Research Foundation, Incorporated
/*
 *  groups.h
 *  
 *
 *  Created by Jeff McKinstry on 4/29/10.
 *
 */

#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
#include <algorithm>
#include <vector>
#include <map>
#include "areas.h"

#ifndef STRINGIZE
#define STRINGIZE(x) (#x)
#endif // !STRINGIZE

#ifndef MAKE_STRING
#define MAKE_STRING(x) STRINGIZE(x)
#endif // !MAKE_STRING

using namespace std;

#ifndef GROUPS
#define GROUPS

class group{
public:
	string area_name;
	string cell_name;
	int rows;
	int cols;
	int first_neuron_id;
	int last_neuron_id;
	float x0,y0,area_width_mm;  // Extra info; redundant info for each group about the area that contains the group, for convenience.
								// This info is not found in the groups.dat file.
	
	group(){
		area_name = "";
		cell_name = "";
		rows = -1;cols=-1;
		first_neuron_id = 1;
		last_neuron_id = 0;
		x0=y0=area_width_mm=0.0;
	}
	
	group(string iarea_name,
		  string icell_name,
		  int irows,
		  int icols,
		  int ifirst_neuron_id,
		  int ilast_neuron_id,
		  float ix0=0,
		  float iy0=0,
		  float iarea_width_mm=0 ){
		area_name = iarea_name;
		cell_name = icell_name;
		rows = irows;
		cols = icols;
		first_neuron_id = ifirst_neuron_id;
		last_neuron_id = ilast_neuron_id;
		x0=ix0;
		y0=iy0;
		area_width_mm=iarea_width_mm;		
	}

	// Pre: fs_group_list is open for writing.
	void write(FILE* fs_group_list){		
		fprintf(fs_group_list,"%s\n",area_name.c_str());
		fprintf(fs_group_list,"%s\n",cell_name.c_str());
		fprintf(fs_group_list,"%d %d %d %d\n",rows, cols, first_neuron_id, last_neuron_id );
	}
	
};



class groups{

public:
	
	//**************************************************************************************
	// Load group info from file
	void load_groups(const char fname[])
	{
		cout << "Loading groups ...\n";
		
		

		areas area_data;
		area_data.load_areas("areas.dat");
		
		
		max_neuron_id = -1;
		group g;
		fstream gfile(fname);
		while(gfile >> g.area_name)
		{
			gfile >> g.cell_name >> g.rows >> g.cols >> g.first_neuron_id >> g.last_neuron_id;
			cout << g.area_name << ":" <<  g.cell_name << " has " << g.rows*g.cols << " neurons." << endl;
			if ( area_data.exists(g.area_name) ){
				areas::area a=area_data.get_area(g.area_name);
				g.x0 = a.x0;
				g.y0 = a.y0;
				g.area_width_mm = a.width_mm;
			}
			else{
				cerr << "Can't find area name " << g.area_name << "in area.dat while reading groups.dat! Terminating."<< endl;
				exit(1);
			}
			group_data[g.area_name+g.cell_name]=g;
			
			if( g.last_neuron_id > max_neuron_id   ){
				max_neuron_id = g.last_neuron_id;
			}
		}
		
		gfile.close();
		
	}; // load_Groups

	
	void load_groups(group igroup_data[MAX_AREAS][MAX_TYPES])
	{
		
		areas area_data;
		area_data.load_areas("areas.dat");
				
		max_neuron_id = -1;
		
		for(int area = 0; area < area_data.get_N_areas(); area++){
			for(int type = 0; type < MAX_TYPES; type++){
				
				if( igroup_data[area][type].area_name != "" ){
					group g=igroup_data[area][type];
					group_data[g.area_name+g.cell_name]=g;
					
					if( g.last_neuron_id > max_neuron_id   ){
						max_neuron_id = g.last_neuron_id;
					}
				}
			}
		}
		
	}; // load_Groups
	
	
	
	bool exists(string group_name){
	
		return (group_data.find(group_name)!=group_data.end());
		
	}
	
	int get_max_neuron_id(){
		return max_neuron_id;
	}
	
	group operator[](string group_name){
		return group_data[group_name];
	}
	
	
	map<string, group> get_map(){
		return group_data;
	}
	
private:
	
	map<string, group> group_data;
	int max_neuron_id;
	

};

#endif
